package com.iscas.dataaggregation.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iscas.dataaggregation.domain.experiment.Faultinnernode;
import com.iscas.dataaggregation.mapper.mysql.FaultinnernodeMapper;
import com.iscas.dataaggregation.strategy.ChaosFaultTypeContext;
import com.iscas.dataaggregation.strategy.ChaosFaultTypeStrategy;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.NodeList;
import io.fabric8.kubernetes.api.model.ServiceList;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Component
public class ChaosFaultUtils {

    @Autowired
    private FaultinnernodeMapper faultinnernodeMapper;

    @Autowired
    private KubernetesClient kubernetesClient;

    @Autowired
    private ChaosFaultTypeContext chaosFaultTypeContext;

    @Autowired
    private ServicesUtils servicesUtils;
    private static final Logger logger = Logger.getLogger(ChaosFaultUtils.class);

    public String getChaosNameByConfigId(int faultConfigId, String nodeType) {
        logger.info("Start processing fault_config_id: " + faultConfigId + " with nodeType: " + nodeType);

        // 查询所有符合条件的记录
        List<Faultinnernode> nodes = faultinnernodeMapper.selectByFaultConfigIdAndNodeType(faultConfigId, nodeType);

        if (nodes == null || nodes.isEmpty()) {
            String message = "No " + nodeType + " node found for fault_config_id: " + faultConfigId;
            logger.warn(message);
            return message;
        }

        // 获取第一条记录
        Faultinnernode node = nodes.get(0);
        logger.info("Found Inject node with ID: " + node.getId() + ", processing content...");

        try {
            // 解析 content 字段为 Map
            Map<String, Object> contentData = parseJson(node.getContent());
            if (contentData == null) {
                String message = "Failed to parse content for fault_config_id: " + faultConfigId;
                logger.error(message);
                return message;
            }

            // 获取 chaosType（一级故障类型）
            String chaosType = (String) contentData.get("chaosType");
            logger.info("Detected chaosType: " + chaosType);

            // 根据 chaosType 选择对应的策略
            ChaosFaultTypeStrategy strategy = chaosFaultTypeContext.getStrategy(chaosType);
            if (strategy == null) {
                String message = "No strategy found for chaosType: " + chaosType;
                logger.warn(message);
                return message;
            }

            // 调用策略获取拼接后的故障类型
            String faultType = strategy.getFaultType(contentData);
            logger.info("Generated faultType: " + faultType + " for chaosType: " + chaosType);
            return faultType;

        } catch (Exception e) {
            String message = "Error processing fault_config_id: " + faultConfigId + ", details: " + e.getMessage();
            logger.error(message, e);
            return message;
        }
    }

    /**
     * 根据 fault_config_id 获取节点或服务名称
     *
     * @param faultConfigId 故障配置 ID
     * @return 节点或服务名称
     */
    public String getNodeOrServiceNameByFaultConfigId(int faultConfigId) {
        logger.info("Starting to process fault_config_id: " + faultConfigId);

        // 查询 Inject 节点
        List<Faultinnernode> nodes = faultinnernodeMapper.selectByFaultConfigIdAndNodeType(faultConfigId, "Inject");
        if (nodes == null || nodes.isEmpty()) {
            logger.warn("No Inject node found for fault_config_id: " + faultConfigId);
            return "No Inject node found for fault_config_id: " + faultConfigId;
        }

        Faultinnernode node = nodes.get(0);
        logger.info("Found Inject node with ID: " + node.getId() + ", processing content...");

        // 解析 content 字段
        Map<String, Object> contentData = parseJson(node.getContent());
        if (contentData == null) {
            logger.error("Failed to parse content for fault_config_id: " + faultConfigId);
            return "Failed to parse content for fault_config_id: " + faultConfigId;
        }

        // 获取 chaosType
        String chaosType = (String) contentData.get("chaosType");
        logger.info("Detected chaosType: " + chaosType);

        // 判断是 PhysicalMachineChaos 还是服务类型
        if ("PhysicalMachineChaos".equals(chaosType)) {
            logger.info("Handling PhysicalMachineChaos for fault_config_id: " + faultConfigId);
            return handlePhysicalMachineChaos(contentData);
        } else {
            logger.info("Handling service chaos for fault_config_id: " + faultConfigId);
            return handleServiceChaos(contentData);
        }
    }

    /**
     * 处理 PhysicalMachineChaos 类型，返回节点名称
     *
     * @param contentData 解析后的 content 数据
     * @return 节点名称
     */
    private String handlePhysicalMachineChaos(Map<String, Object> contentData) {
        try {
            List<String> addresses = (List<String>) ((Map<String, Object>) contentData.get("PhysicalMachineChaos")).get("address");
            if (addresses == null || addresses.isEmpty()) {
                logger.warn("No address found for PhysicalMachineChaos");
                return "No address found for PhysicalMachineChaos";
            }

            String address = addresses.get(0).split(":")[0];
            logger.info("Extracted IP address: " + address);

            NodeList nodeList = kubernetesClient.nodes().list();
            for (Node node : nodeList.getItems()) {
                List<io.fabric8.kubernetes.api.model.NodeAddress> nodeAddresses = node.getStatus().getAddresses();
                if (nodeAddresses != null) {
                    for (io.fabric8.kubernetes.api.model.NodeAddress nodeAddress : nodeAddresses) {
                        if ("InternalIP".equals(nodeAddress.getType()) && address.equals(nodeAddress.getAddress())) {
                            logger.info("Matched node for IP: " + address + ", Node Name: " + node.getMetadata().getName());
                            return node.getMetadata().getName();
                        }
                    }
                }
            }
            logger.warn("No matching node found for IP: " + address);
            return "No matching node found for IP: " + address;
        } catch (Exception e) {
            logger.error("Error processing PhysicalMachineChaos: ", e);
            return "Error processing PhysicalMachineChaos";
        }
    }

    /**
     * 处理服务类型（非 PhysicalMachineChaos），返回服务名称
     *
     * @param contentData 解析后的 content 数据
     * @return 服务名称
     */
    private String handleServiceChaos(Map<String, Object> contentData) {
        try {
            Map<String, Object> selector = (Map<String, Object>) ((Map<String, Object>) contentData.get(contentData.get("chaosType"))).get("selector");

            logger.info("selector: " + selector);
            if (selector == null) {
                logger.warn("No selector found for service chaos");
                return "No selector found for service chaos";
            }

            List<String> namespaces = (List<String>) selector.get("namespaces");
            if (namespaces == null || namespaces.isEmpty()) {
                logger.warn("No namespaces found in selector");
                return "No namespaces found in selector";
            }
            String namespace = namespaces.get(0);

            Map<String, String> labelSelectors = (Map<String, String>) selector.get("labelSelectors");
            if (labelSelectors == null || labelSelectors.isEmpty()) {
                logger.warn("No labelSelectors found in selector");
                return "No labelSelectors found in selector";
            }

            String serviceName = servicesUtils.getServiceNamesByNamespaceAndSelector(namespace, labelSelectors).get(0);
            logger.info("Matched service name: " + serviceName);
            return serviceName;
        } catch (Exception e) {
            logger.error("Error processing service chaos: ", e);
            return "Error processing service chaos";
        }
    }

    /**
     * 将 JSON 字符串解析为 Map
     *
     * @param jsonString JSON 字符串
     * @return 解析后的 Map
     */
    private Map<String, Object> parseJson(String jsonString) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(jsonString, Map.class);
        } catch (Exception e) {
            logger.error("Failed to parse JSON content: ", e);
            return null;
        }
    }

}
